package com.ang.jwt.util;
import com.alibaba.fastjson.JSONObject;
import com.ang.jwt.constant.SystemConstant;
import com.ang.jwt.entity.CheckResult;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.util.encoders.Base64;
/**
 * jwt加密和解密的工具类
 * 创建者 科帮网
 * 创建时间 2017年11月24日
 */
public class JwtUtils {
	/**
	 * 签发JWT
	 * @Author  科帮网
	 * @param id
	 * @param subject 可以是JSON数据 尽可能少
	 * @param ttlMillis
	 * @return  String
	 * @Date	2017年11月24日
	 * 2017年11月24日  张志朋  首次创建
	 *
	 */
	public static String createJWT(String id, String subject, long ttlMillis) {
		System.out.println("开始:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
		long nowMillis = System.currentTimeMillis();
		Date now = new Date(nowMillis);
		SecretKey secretKey = generalKey();
		JwtBuilder builder = Jwts.builder()
				.setId(id)
				.setSubject(subject)   // 主题
				.setIssuer("科帮网")     // 签发者
				.setIssuedAt(now)      // 签发时间
				.signWith(signatureAlgorithm, secretKey); // 签名算法以及密匙
		if (ttlMillis >= 0) {
			long expMillis = nowMillis + ttlMillis;
			Date expDate = new Date(expMillis);
			builder.setExpiration(expDate); // 过期时间
		}

		//使用claim，不会覆盖setId,setSubject,setIssuer等
		builder.claim("name","张三")
				.claim("age","28");

		//构建要保存的自定义信息
		Map<String, Object> infoMap = new HashMap<>();
		infoMap.put("name","张三");
		infoMap.put("age",28);
		infoMap.put("sex","男");
		//builder添加map作为claims，此时上面setId,setSubject,setIssuer将全部失效
		//builder.setClaims(infoMap);

		JSONObject obj = new JSONObject(infoMap);
		String info = obj.toString();
		//builder定义payload，此时会报错，因为上面的setId,setSubject,setIssuer属于claims，而claims和payload不能同时存在
		//builder.setPayload(info);

		String token = builder.compact();
		System.out.println("结束:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		return token;
	}

	/**
	 * 验证JWT
	 * @param jwtStr
	 * @return
	 */
	public static CheckResult validateJWT(String jwtStr) {
		CheckResult checkResult = new CheckResult();
		Claims claims = null;
		try {
			claims = parseJWT(jwtStr);
			checkResult.setSuccess(true);
			checkResult.setClaims(claims);
		} catch (ExpiredJwtException e) {
			checkResult.setErrCode(SystemConstant.JWT_ERRCODE_EXPIRE);
			checkResult.setSuccess(false);
		} catch (SignatureException e) {
			checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
			checkResult.setSuccess(false);
		} catch (Exception e) {
			checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
			checkResult.setSuccess(false);
		}
		return checkResult;
	}

	/**
	 *
	 * 解析JWT字符串
	 * @param jwt
	 * @return
	 * @throws Exception
	 */
	public static Claims parseJWT(String jwt) throws Exception {
		SecretKey secretKey = generalKey();
		return Jwts.parser()
				.setSigningKey(secretKey)
				.parseClaimsJws(jwt)
				.getBody();
	}

	/**
	 * 获取加密后的秘钥
	 * @return
	 */
	public static SecretKey generalKey() {
		byte[] encodedKey = Base64.decode(SystemConstant.JWT_SECERT);
	    SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
	    return key;
	}
}
